#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<ctype.h>
#include<fcntl.h>

#define LEFT  "["
#define RIGHT "]"
#define MABLE "$"
#define DELINE " \t"
#define SIZE  1024
#define EXIT_CODE 2
#define NONE -1
#define IN_RDIR 0
#define OUT_RDIR 1
#define APPEND_RDIR 2

int myenvi=0;
int lastcode=0;
char pwd[SIZE];
char cline[SIZE];
char* argv[SIZE];
char myenv[SIZE];
extern char**environ;
char*rdirfilename=NULL;
int rdir=NONE;

void check_redir(char*cmd){//检查是否有重定向操作
    char *pos=cmd;
    while(*pos)
    {
        if(*pos=='>'){
            if(*(pos+1)=='>'){
                *pos++='\0';
                *pos++='\0';
                 while(isspace(*pos))
                     pos++;
                 rdirfilename=pos;
                 rdir=APPEND_RDIR;
                 break;
            }       
            else{
                *pos++='\0';
                while(isspace(*pos))pos++;
                rdirfilename=pos;
                rdir=OUT_RDIR;
                break;
            }
        }
        else if(*pos=='<') {
            *pos++='\0';
            while(isspace(*pos))pos++;
            rdirfilename=pos;
            rdir=IN_RDIR;
            break;
        }
        else {

        }
        pos++;
    }
}

void getpwd(){//获取当前目录
    getcwd(pwd,sizeof(pwd));
}

const char* getuser(){//获取当前目录
    return getenv("USER");
}

const char* _gethostname(){
    return getenv("HOSTNAME");
}
void Normalcommand(char*_argv[])//调用外部命令
{
  pid_t id=fork();//创建子进程
  if(id<0)
  {
      perror("fork");
      return; 
  }
  else if(id==0)
  {
      int fd=0;
      if(rdir==IN_RDIR){//进行重定向操作
          fd=open(rdirfilename,O_RDONLY);
          dup2(fd,0);
      }
      else if(rdir==OUT_RDIR){
          fd=open(rdirfilename,O_CREAT|O_WRONLY|O_TRUNC,0666);
          dup2(fd,1);
      }
      else if(rdir==APPEND_RDIR)
      {
          fd=open(rdirfilename,O_CREAT|O_WRONLY|O_APPEND,0666);
          dup2(fd,1);
      }
      execvp(_argv[0],_argv);//进程替换
      perror("execvp");//运行失败
      exit(EXIT_CODE);
  }
  else{
      int status=0;
      pid_t ret= waitpid(id,&status,0);//等待子进程退出
      if(ret==id)
      lastcode=WEXITSTATUS(status);//获取进程退出码
  }
}

int Bulidcommand(char* _argv[],int argc){//内建命令
   // printf("%s\n",argv[0]);
    if(strcmp(_argv[0],"cd")==0 && argc==2){//cd命令
         if(chdir(_argv[1])!=0)
            perror("cd");
            getpwd();
            return 1;
    }
    else if(argc==2&&strcmp(_argv[0],"export")==0){
        strcpy(myenv,_argv[1]);
        putenv(myenv);
        return 1;
    }
    else if(argc==2&&strcmp(_argv[0],"echo")==0)
    {
        if(strcmp(_argv[1],"$?")==0)
        {
            printf("%d\n",lastcode);
            return 1;
        }
        else if(*_argv[1]=='$')
        {
           char* str=getenv(_argv[1]+1);
           if(str)
           printf("%s\n",str);
           return 1;
        }
        else printf("%s\n",_argv[1]);
        return 1;
    }
    if(strcmp(_argv[0],"ls")==0)
    {
       _argv[argc++]="--color";
       _argv[argc]=NULL;
    }
    return 0;
}

int splict()//分割字符串
{
    int i=0;
    argv[i++]=strtok(cline,DELINE);
    while(argv[i++]=strtok(NULL,DELINE));

    return i-1;
}

void interact(){//命令行
    getpwd();
   // printf("%s\n",pwd);
    printf(LEFT"%s@%s %s"RIGHT MABLE" ",getuser(),_gethostname(),pwd);
   // sleep(1);
    fgets(cline,sizeof(cline),stdin);
   // printf("%s",cline);
    cline[strlen(cline)-1]='\0';
    
    check_redir(cline);
}

int main()
{
    while(1)
    {
        
      rdirfilename=NULL;
      rdir=NONE;
       // chdir("12-5");
       interact();
       int a=splict();
       if(a==0) continue;
       int num= Bulidcommand(argv,a);
       if(!num) Normalcommand(argv);
    }
}
